/**
 *    Copyright 2006-2017 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.mybatis.generator.plugins;

import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.plugins.custome.CustomerConstants;

import java.util.ArrayList;
import java.util.List;

import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;
import static org.mybatis.generator.internal.util.messages.Messages.getString;
import static org.mybatis.generator.plugins.custome.CustomerConstants.*;

/**
 * 生成 service ,serviceImpl
 */
public class AdditionalServiceGeneratorPlugin extends PluginAdapter {

    // 项目目录，一般为 src/main/java
    private String targetProject;

    // service包名， 
    private String servicePackage;//[config]

    // service实现类包名， 
    private String serviceImplPackage;//[config]

    // service接口名后缀
    private String serviceSuffix;//default(Service)[config] 

    // service接口的父接口
    private String superServiceInterface;

    // service实现类的父类
    private String superServiceImpl;

    private String serviceImportTypes;//service自定义引入的类  [config]

    private String serviceImplImportTypes;//serviceImpl自定义引入的类  [config]

    private static final String import_split = ";";//引入类的分隔符  [config]

    private String recordType;

    private String modelName;

    private FullyQualifiedJavaType model;

    private String serviceName;
    private String serviceImplName;
    private String dtoPackage;//dto 的包路径   //[config]
    private String dtoSuffix;//dto 后缀 (default: DTO)
    private boolean isNeeded;//是否要生成该文件 (default:false)  //[config]

    private TopLevelClass modelClazzDTO;//dto class

    @Override
    public boolean validate(List<String> warnings) {
        boolean valid = true;

        if (!stringHasValue(properties.getProperty("servicePackage"))) { //$NON-NLS-1$
            warnings.add(getString("ValidationError.18", //$NON-NLS-1$
                    "AdditionalServiceGeneratorPlugin", //$NON-NLS-1$
                    "servicePackage")); //$NON-NLS-1$
            valid = false;
        }

        if (!stringHasValue(properties.getProperty("serviceImplPackage"))) { //$NON-NLS-1$
            warnings.add(getString("ValidationError.18", //$NON-NLS-1$
                    "AdditionalServiceGeneratorPlugin", //$NON-NLS-1$
                    "serviceImplPackage")); //$NON-NLS-1$
            valid = false;
        }

        if (!stringHasValue(properties.getProperty("dtoPackage"))) { //$NON-NLS-1$
            warnings.add(getString("ValidationError.18", //$NON-NLS-1$
                    "AdditionalServiceGeneratorPlugin", //$NON-NLS-1$
                    "dtoPackage")); //$NON-NLS-1$
            valid = false;
        }

        targetProject = properties.getProperty("targetProject");
        servicePackage = properties.getProperty("servicePackage");
        serviceImplPackage = properties.getProperty("serviceImplPackage");
        serviceSuffix = properties.getProperty("serviceSuffix");
        serviceSuffix = stringHasValue(serviceSuffix) ? serviceSuffix : "Service";
        superServiceInterface = properties.getProperty("superServiceInterface");
        superServiceImpl = properties.getProperty("superServiceImpl");
        dtoPackage = properties.getProperty("dtoPackage");
        serviceImportTypes = properties.getProperty("serviceImportTypes");
        serviceImplImportTypes = properties.getProperty("serviceImplImportTypes");
        dtoSuffix = properties.getProperty("dtoSuffix") == null ? "DTO" : properties.getProperty("dtoSuffix");
        isNeeded = properties.getProperty("isNeeded").equalsIgnoreCase("true") ? true : false;//default

        return valid;
    }

    @Override
    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {
        if (isNeeded) {
            recordType = introspectedTable.getBaseRecordType();
            modelName = recordType.substring(recordType.lastIndexOf(".") + 1);
            model = new FullyQualifiedJavaType(recordType);
            String daoPackage = introspectedTable.getContext().getJavaClientGeneratorConfiguration().getTargetPackage();
            //check target project
            if (!stringHasValue(targetProject)) {
                //default same as dao file
                targetProject = introspectedTable.getContext().getJavaClientGeneratorConfiguration().getTargetProject();
            }
            //check dto exist
            if (stringHasValue(dtoPackage)) {
                String dtoClassName = String.format("%s.%s%s", dtoPackage, modelName, dtoSuffix);
                modelClazzDTO = new TopLevelClass(new FullyQualifiedJavaType(dtoClassName));
            } else {
                //if not define dto package ,use model package
                String modelPackage = introspectedTable.getContext().getJavaModelGeneratorConfiguration().getTargetPackage();
                String defaultDtoClassName = String.format("%s.%s%s", modelPackage, modelName, dtoSuffix);
                modelClazzDTO = new TopLevelClass(new FullyQualifiedJavaType(defaultDtoClassName));
            }
            //
            if (stringHasValue(servicePackage)) {
                serviceName = servicePackage + "." + modelName + serviceSuffix;
            } else {
                //no define service package use dao package
                serviceName = daoPackage + "." + modelName + serviceSuffix;
            }
            if (stringHasValue(serviceImplPackage)) {
                serviceImplName = serviceImplPackage + "." + modelName + serviceSuffix + "Impl";
            } else {
                //no define service implement package use dao package
                serviceImplName = daoPackage + "." + modelName + serviceSuffix + "Impl";
            }
            //build dto 
            List<GeneratedJavaFile> answer = new ArrayList<GeneratedJavaFile>();
            GeneratedJavaFile gjf = generateServiceInterface(introspectedTable, model);
            GeneratedJavaFile gjf2 = generateServiceImpl(introspectedTable, model);
            answer.add(gjf);
            answer.add(gjf2);
            //add
            return answer;
        } else {
            //not needed  (default)
            return null;
        }
    }

    // 生成service接口
    private GeneratedJavaFile generateServiceInterface(IntrospectedTable introspectedTable, FullyQualifiedJavaType model) {
        String shortName = model.getShortNameWithoutTypeArguments();
        FullyQualifiedJavaType service = new FullyQualifiedJavaType(serviceName);
        Interface serviceInterface = new Interface(service);
        serviceInterface.setVisibility(JavaVisibility.PUBLIC);
        serviceInterface.addImportedType(modelClazzDTO.getType());
        serviceInterface.addImportedType(new FullyQualifiedJavaType("java.util.List"));
        //check import
        if (stringHasValue(serviceImportTypes)) {
            String[] split = serviceImportTypes.split(import_split);
            for (String type : split) {
                serviceInterface.addImportedType(new FullyQualifiedJavaType(type.trim()));
            }
        } else {
            //not define ,use default. need change
            serviceInterface.addImportedType(new FullyQualifiedJavaType("org.mybatis.generator.plugins.custome.Result"));
            serviceInterface.addImportedType(new FullyQualifiedJavaType("org.mybatis.generator.plugins.custome.PageQuery"));
        }
        // 添加父接口
        if (stringHasValue(superServiceInterface)) {
            String superServiceInterfaceName = superServiceInterface.substring(superServiceInterface.lastIndexOf(".") + 1);
            serviceInterface.addImportedType(new FullyQualifiedJavaType(superServiceInterface));
            serviceInterface.addImportedType(new FullyQualifiedJavaType(recordType));
            serviceInterface.addSuperInterface(new FullyQualifiedJavaType(superServiceInterfaceName + "<" + modelName + ">"));
        }
        FullyQualifiedJavaType modelClazzDTOType = modelClazzDTO.getType();
        String dtoParameter = firstCharToLowCase(modelClazzDTOType.getShortName());
        //add method
        Method addMethod = new Method();
        addMethod.setName(CustomerConstants.generateMethod(CustomerConstants.SERVICE_ADD_ONE, shortName));
        addMethod.setVisibility(JavaVisibility.PUBLIC);
        addMethod.setReturnType(new FullyQualifiedJavaType(CustomerConstants.generateIntResult()));
        addMethod.addParameter(new Parameter(modelClazzDTOType, dtoParameter));
        addMethod.addJavaDocLine("//新增");
        //add method
        Method delMethod = new Method();
        delMethod.setName(CustomerConstants.generateMethod(CustomerConstants.SERVICE_DELETE_BY_ID, shortName));
        delMethod.setReturnType(new FullyQualifiedJavaType(CustomerConstants.generateBooleanResult()));
        delMethod.setVisibility(JavaVisibility.PUBLIC);
        delMethod.addParameter(new Parameter(FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper(), "id"));
        delMethod.addParameter(new Parameter(FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper(), "userId"));
        delMethod.addJavaDocLine("//逻辑删除");
        //select by primary key
        Method selectIdMethod = new Method();
        selectIdMethod.setName(CustomerConstants.generateMethod(CustomerConstants.SERVICE_SELECT_BY_ID, shortName));
        selectIdMethod.setVisibility(JavaVisibility.PUBLIC);
        selectIdMethod.setReturnType(new FullyQualifiedJavaType(CustomerConstants.generateDTOResult(shortName)));
        selectIdMethod.addParameter(new Parameter(FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper(), "id"));
        selectIdMethod.addJavaDocLine("//根据主键查询");
        //update by id
        Method updateIdMethod = new Method();
        updateIdMethod.setName(CustomerConstants.generateMethod(CustomerConstants.SERVICE_UPDATE_BY_ID, shortName));
        updateIdMethod.setReturnType(new FullyQualifiedJavaType(CustomerConstants.generateBooleanResult()));
        updateIdMethod.setVisibility(JavaVisibility.PUBLIC);
        updateIdMethod.addParameter(new Parameter(modelClazzDTOType, dtoParameter));
        updateIdMethod.addJavaDocLine("//根据主键更新");
        //select by example
        Method selectExampleMethod = new Method();
        selectExampleMethod.setName(CustomerConstants.generateMethod(CustomerConstants.SERVICE_SELECT_BY_EXAMPLE, shortName));
        selectExampleMethod.setVisibility(JavaVisibility.PUBLIC);
        selectExampleMethod.setReturnType(new FullyQualifiedJavaType(CustomerConstants.generateListDTOResult(shortName)));
        selectExampleMethod.addParameter(new Parameter(modelClazzDTOType, dtoParameter));
        selectExampleMethod.addJavaDocLine("//查询集合");
        //select page
        Method selectPageMethod = new Method();
        selectPageMethod.setName(CustomerConstants.generateMethod(CustomerConstants.SERVICE_SELECT_PAGE, shortName));
        selectPageMethod.setReturnType(new FullyQualifiedJavaType(CustomerConstants.generatePageDTOResult(shortName)));
        selectPageMethod.setVisibility(JavaVisibility.PUBLIC);
        selectPageMethod.addParameter(new Parameter(modelClazzDTOType, dtoParameter));
        selectPageMethod.addParameter(new Parameter(new FullyQualifiedJavaType("int"), "pageSize"));
        selectPageMethod.addParameter(new Parameter(new FullyQualifiedJavaType("int"), "page"));
        selectPageMethod.addParameter(new Parameter(new FullyQualifiedJavaType("String"), "orderByClause"));
        selectPageMethod.addJavaDocLine("//分页查询");
        //汇总
        serviceInterface.addMethod(addMethod);
        serviceInterface.addMethod(delMethod);
        serviceInterface.addMethod(selectIdMethod);
        serviceInterface.addMethod(updateIdMethod);
        serviceInterface.addMethod(selectExampleMethod);
        serviceInterface.addMethod(selectPageMethod);
        GeneratedJavaFile gjf = new GeneratedJavaFile(serviceInterface, targetProject, context.getJavaFormatter());
        return gjf;
    }

    // 生成service实现类
    private GeneratedJavaFile generateServiceImpl(IntrospectedTable introspectedTable, FullyQualifiedJavaType model) {
        String shortName = model.getShortNameWithoutTypeArguments();//model name
        String shortModelParam = firstCharToLowCase(shortName);
        FullyQualifiedJavaType modelClazzDTOType = modelClazzDTO.getType();//dto
        String dtoShortClassName = modelClazzDTOType.getShortName();
        String dtoParameter = firstCharToLowCase(dtoShortClassName);
        String exampleClass = introspectedTable.getExampleType();//example
        String exampleShort = exampleClass.substring(exampleClass.lastIndexOf('.') + 1);
        String daoFieldType = introspectedTable.getMyBatis3JavaMapperType();//mapper type
        String daoFieldName = firstCharToLowCase(daoFieldType.substring(daoFieldType.lastIndexOf(".") + 1));//mapper name

        FullyQualifiedJavaType service = new FullyQualifiedJavaType(serviceName);
        FullyQualifiedJavaType serviceImpl = new FullyQualifiedJavaType(serviceImplName);
        TopLevelClass clazz = new TopLevelClass(serviceImpl);
        clazz.setVisibility(JavaVisibility.PUBLIC);
        clazz.addSuperInterface(service);
        //common
        clazz.addImportedType(new FullyQualifiedJavaType("java.util.List"));
        clazz.addImportedType(new FullyQualifiedJavaType("java.util.Date"));
        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.stereotype.Service"));
        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.beans.factory.annotation.Autowired"));
        clazz.addImportedType(new FullyQualifiedJavaType("com.alibaba.fastjson.JSON"));
        clazz.addImportedType(model);
        clazz.addImportedType(new FullyQualifiedJavaType(exampleClass));
        clazz.addImportedType(service);
        clazz.addImportedType(new FullyQualifiedJavaType(daoFieldType));
        clazz.addImportedType(modelClazzDTO.getType());
        //define class
        if (stringHasValue(serviceImplImportTypes)) {
            String[] split = serviceImplImportTypes.split(import_split);
            for (String type : split) {
                clazz.addImportedType(type);
            }
        } else {
            //not define imports ,need change
            clazz.addImportedType(new FullyQualifiedJavaType("org.mybatis.generator.plugins.custome.Result"));
            clazz.addImportedType(new FullyQualifiedJavaType("org.mybatis.generator.plugins.custome.PageQuery"));
            clazz.addImportedType(new FullyQualifiedJavaType("org.mybatis.generator.plugins.custome.NewBstBeanUtils"));
            clazz.addImportedType(new FullyQualifiedJavaType("org.mybatis.generator.plugins.custome.ResponseCode"));
        }

        if (stringHasValue(superServiceImpl)) {
            String superServiceImplName = superServiceImpl.substring(superServiceImpl.lastIndexOf(".") + 1);
            clazz.addImportedType(superServiceImpl);
            clazz.addImportedType(recordType);
            clazz.setSuperClass(superServiceImplName + "<" + modelName + ">");
        }
        clazz.addAnnotation("@Service");

        Field daoField = new Field(daoFieldName, new FullyQualifiedJavaType(daoFieldType));
        daoField.addAnnotation("@Autowired");
        daoField.setVisibility(JavaVisibility.PRIVATE);
        clazz.addField(daoField);
        //add method
        Method addMethod = new Method(CustomerConstants.generateMethod(CustomerConstants.SERVICE_ADD_ONE, shortName));
        addMethod.addAnnotation("@Override");
        addMethod.setVisibility(JavaVisibility.PUBLIC);
        addMethod.setReturnType(new FullyQualifiedJavaType(CustomerConstants.generateIntResult()));
        addMethod.addParameter(new Parameter(modelClazzDTOType, dtoParameter));
        addMethod.addJavaDocLine("//新增");
        List<String> addMethodBody = new ArrayList<String>();
        generateServiceAddCodes(shortName, dtoParameter, daoFieldName, addMethodBody);
        addMethod.addBodyLines(addMethodBody);
        //delete id logic
        Method delMethod = new Method(CustomerConstants.generateMethod(CustomerConstants.SERVICE_DELETE_BY_ID, shortName));
        delMethod.addAnnotation("@Override");
        delMethod.setReturnType(new FullyQualifiedJavaType(CustomerConstants.generateBooleanResult()));
        delMethod.setVisibility(JavaVisibility.PUBLIC);
        delMethod.addParameter(new Parameter(FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper(), "id"));
        delMethod.addParameter(new Parameter(FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper(), "userId"));
        delMethod.addJavaDocLine("//逻辑删除");
        generateDeleteIdLogicCode(shortName, shortModelParam, exampleShort, daoFieldName, delMethod);
        //select by id
        Method selectIdMethod = new Method(CustomerConstants.generateMethod(CustomerConstants.SERVICE_SELECT_BY_ID, shortName));
        selectIdMethod.addAnnotation("@Override");
        selectIdMethod.setVisibility(JavaVisibility.PUBLIC);
        selectIdMethod.setReturnType(new FullyQualifiedJavaType(CustomerConstants.generateDTOResult(shortName)));
        selectIdMethod.addParameter(new Parameter(FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper(), "id"));
        selectIdMethod.addJavaDocLine("//根据主键查询");
        generateSelectByIdCode(shortName, shortModelParam, modelClazzDTOType, exampleClass, exampleShort, dtoParameter, daoFieldName, selectIdMethod);
        //update by id
        Method updateIdMethod = new Method(CustomerConstants.generateMethod(CustomerConstants.SERVICE_UPDATE_BY_ID, shortName));
        updateIdMethod.addAnnotation("@Override");
        updateIdMethod.setReturnType(new FullyQualifiedJavaType(CustomerConstants.generateBooleanResult()));
        updateIdMethod.setVisibility(JavaVisibility.PUBLIC);
        updateIdMethod.addParameter(new Parameter(modelClazzDTOType, dtoParameter));
        updateIdMethod.addJavaDocLine("//根据主键更新");
        generateUpdateByIdCode(shortName, shortModelParam, exampleClass, exampleShort, dtoParameter, daoFieldName, updateIdMethod);
        //select by example
        Method selectExampleMethod = new Method(CustomerConstants.generateMethod(CustomerConstants.SERVICE_SELECT_BY_EXAMPLE, shortName));
        selectExampleMethod.addAnnotation("@Override");
        selectExampleMethod.setVisibility(JavaVisibility.PUBLIC);
        selectExampleMethod.setReturnType(new FullyQualifiedJavaType(CustomerConstants.generateListDTOResult(shortName)));
        selectExampleMethod.addParameter(new Parameter(modelClazzDTOType, dtoParameter));
        selectExampleMethod.addJavaDocLine("//查询集合");
        generateSelectExampleCode(shortName, dtoShortClassName, dtoParameter, exampleShort, daoFieldName, selectExampleMethod);
        //select page
        Method selectPageMethod = new Method(CustomerConstants.generateMethod(CustomerConstants.SERVICE_SELECT_PAGE, shortName));
        selectPageMethod.addAnnotation("@Override");
        selectPageMethod.setReturnType(new FullyQualifiedJavaType(CustomerConstants.generatePageDTOResult(shortName)));
        selectPageMethod.setVisibility(JavaVisibility.PUBLIC);
        selectPageMethod.addParameter(new Parameter(modelClazzDTOType, dtoParameter));
        selectPageMethod.addParameter(new Parameter(new FullyQualifiedJavaType("int"), "pageSize"));
        selectPageMethod.addParameter(new Parameter(new FullyQualifiedJavaType("int"), "page"));
        selectPageMethod.addParameter(new Parameter(new FullyQualifiedJavaType("String"), "orderByClause"));
        selectPageMethod.addJavaDocLine("//分页查询");
        generateSelectPageCode(shortName, dtoShortClassName, dtoParameter, exampleShort, daoFieldName, selectPageMethod);
        //build query 
        Method buildQueryMethod = new Method(CustomerConstants.SERVICE_BUILD_QUERY);
        buildQueryMethod.setVisibility(JavaVisibility.PRIVATE);
        buildQueryMethod.addParameter(new Parameter(modelClazzDTOType, dtoParameter));
        FullyQualifiedJavaType criteriaType = new FullyQualifiedJavaType(exampleClass + ".Criteria");
        buildQueryMethod.addParameter(new Parameter(criteriaType, "criteria"));
        buildQueryMethod.addJavaDocLine("//构建查询对象");
        buildCriteriaQuery(introspectedTable, dtoParameter, buildQueryMethod);

        //汇总
        clazz.addMethod(addMethod);
        clazz.addMethod(delMethod);
        clazz.addMethod(selectIdMethod);
        clazz.addMethod(updateIdMethod);
        clazz.addMethod(selectExampleMethod);
        clazz.addMethod(selectPageMethod);
        clazz.addMethod(buildQueryMethod);
        GeneratedJavaFile gjf2 = new GeneratedJavaFile(clazz, targetProject, context.getJavaFormatter());
        return gjf2;
    }

    /**
     * 构建查询对象
     *
     * @param introspectedTable
     * @param dtoParameter
     * @param buildQueryMethod
     */
    private void buildCriteriaQuery(IntrospectedTable introspectedTable, String dtoParameter, Method buildQueryMethod) {
        List<IntrospectedColumn> allColumns = introspectedTable.getAllColumns();
        for (IntrospectedColumn column : allColumns) {
            String fieldName = column.getJavaProperty();
            String fieldUpperName = firstCharToUpperCase(fieldName);
            if (isSupportType(column)) {
                buildQueryMethod.addBodyLine("//" + column.getRemarks());
                buildQueryMethod.addBodyLine(String.format("if (%s.get%s() != null) {", dtoParameter, fieldUpperName));
                buildQueryMethod.addBodyLine(String.format("criteria.and%sEqualTo(%s.get%s());", fieldUpperName, dtoParameter, fieldUpperName));
                buildQueryMethod.addBodyLine("}");
            }
        }
    }

    /**
     * 仅支持 integer 和 string 两种类型构建查询
     *
     * @param recordType
     * @return
     */
    private boolean isSupportType(IntrospectedColumn recordType) {
        String jdbcTypeName = recordType.getJdbcTypeName();
        if (jdbcTypeName == null) {
            return false;
        }
        return jdbcTypeName.equalsIgnoreCase("INTEGER") || jdbcTypeName.equalsIgnoreCase("VARCHAR");
    }

    private void generateSelectPageCode(String shortName, String dtoShortClassName, String dtoParameter, String exampleShort, String daoFieldName, Method selectPageMethod) {
        selectPageMethod.addBodyLine(String.format("Result<PageQuery<%s>> result = new Result<PageQuery<%s>>();", dtoShortClassName, dtoShortClassName));
        selectPageMethod.addBodyLine(String.format("if (%s == null) {", dtoParameter));
        selectPageMethod.addBodyLine("return result.setResult(ResponseCode.PARAMETER_ERROR, null, \"参数不可为空\");");
        selectPageMethod.addBodyLine("}");
        selectPageMethod.addBodyLine(String.format("%s example = new %s();", exampleShort, exampleShort));
        selectPageMethod.addBodyLine(String.format("example.setOrderByClause(orderByClause);"));
        selectPageMethod.addBodyLine(String.format("%s.Criteria criteria = example.createCriteria();", exampleShort));
        selectPageMethod.addBodyLine("criteria.andIsDelEqualTo(0);");
        selectPageMethod.addBodyLine(String.format("buildQuery(%s, criteria);", dtoParameter));
        selectPageMethod.addBodyLine("//select count");
        selectPageMethod.addBodyLine(String.format("long totalRecord = %s.countByExample(example);", daoFieldName));
        selectPageMethod.addBodyLine(String.format("example.setPageSize(pageSize);", dtoParameter));
        selectPageMethod.addBodyLine(String.format("example.setPageIndex(page);", dtoParameter));
        selectPageMethod.addBodyLine("example.setTotalRecord((int) totalRecord);");
        selectPageMethod.addBodyLine(String.format("List<%s> resultLists = %s.selectPage(example);", shortName, daoFieldName));
        selectPageMethod.addBodyLine("if (resultLists.size() > 0) {");
        selectPageMethod.addBodyLine(String.format("List<%s> results = NewBstBeanUtils.poList2dtoList(resultLists, %s.class);", dtoShortClassName, dtoShortClassName));
        selectPageMethod.addBodyLine("example.setDataList(results);");
        selectPageMethod.addBodyLine("return result.setResult(example, \"ok\");");
        selectPageMethod.addBodyLine("} else {");
        selectPageMethod.addBodyLine(("return result.setResult(ResponseCode.NULL_RESULT, example, \"无结果\");"));
        selectPageMethod.addBodyLine("}");
    }

    /**
     * select by example
     *
     * @param shortName
     * @param dtoShortClassName
     * @param dtoParameter
     * @param exampleShort
     * @param daoFieldName
     * @param selectExampleMethod
     */
    private void generateSelectExampleCode(String shortName, String dtoShortClassName, String dtoParameter, String exampleShort, String daoFieldName, Method selectExampleMethod) {
        selectExampleMethod.addBodyLine(String.format("Result<List<%s>> result = new Result<List<%s>>();", dtoShortClassName, dtoShortClassName));
        selectExampleMethod.addBodyLine(String.format("if (%s == null) {", dtoParameter));
        selectExampleMethod.addBodyLine("return result.setResult(ResponseCode.PARAMETER_ERROR, null, \"参数不可为空\");");
        selectExampleMethod.addBodyLine("}");
        selectExampleMethod.addBodyLine(String.format("%s example = new %s();", exampleShort, exampleShort));
        selectExampleMethod.addBodyLine(String.format("%s.Criteria criteria = example.createCriteria();", exampleShort));
        selectExampleMethod.addBodyLine("criteria.andIsDelEqualTo(0);");
        selectExampleMethod.addBodyLine(String.format("buildQuery(%s, criteria);", dtoParameter));
        selectExampleMethod.addBodyLine(String.format("List<%s> resultList = %s.selectByExample(example);", shortName, daoFieldName));
        selectExampleMethod.addBodyLine("if (resultList.size() > 0) {");
        selectExampleMethod.addBodyLine(String.format("List<%s> results = NewBstBeanUtils.poList2dtoList(resultList, %s.class);", dtoShortClassName, dtoShortClassName));
        selectExampleMethod.addBodyLine("return result.setResult(results, \"ok\");");
        selectExampleMethod.addBodyLine(" } else {");
        selectExampleMethod.addBodyLine("return result.setResult(ResponseCode.NULL_RESULT, null, \"无结果\");");
        selectExampleMethod.addBodyLine("}");
    }

    /**
     * update by id
     *
     * @param shortName
     * @param shortModelParam
     * @param exampleClass
     * @param exampleShort
     * @param dtoParameter
     * @param daoFieldName
     * @param updateIdMethod
     */
    private void generateUpdateByIdCode(String shortName, String shortModelParam, String exampleClass, String exampleShort, String dtoParameter, String daoFieldName, Method updateIdMethod) {
        updateIdMethod.addBodyLine("Result<Boolean> result = new Result<Boolean>();");
        updateIdMethod.addBodyLine(String.format(" if (%s == null || %s.getId() == null) {", dtoParameter, dtoParameter));
        updateIdMethod.addBodyLine("return result.setResult(ResponseCode.PARAMETER_ERROR, false, \"参数不可为空\");");
        updateIdMethod.addBodyLine("}");
        updateIdMethod.addBodyLine("try {");
        updateIdMethod.addBodyLine("//where");
        updateIdMethod.addBodyLine(String.format("%s example = new %s();", exampleShort, exampleShort));
        updateIdMethod.addBodyLine(String.format("example.createCriteria().andIsDelEqualTo(0).andIdEqualTo(%s.getId());", dtoParameter));
        updateIdMethod.addBodyLine("//update");
        updateIdMethod.addBodyLine(String.format("%s %s = NewBstBeanUtils.dto2Po(%s, %s.class);", shortName, shortModelParam, dtoParameter, shortName));
        updateIdMethod.addBodyLine("//");
        updateIdMethod.addBodyLine(String.format("%s.updateByExampleSelective(%s, example);", daoFieldName, shortModelParam));
        updateIdMethod.addBodyLine("return result.setResult(true, \"ok\");");
        updateIdMethod.addBodyLine("} catch (Exception e) {");
        updateIdMethod.addBodyLine("e.printStackTrace();");
        updateIdMethod.addBodyLine("return result.setResult(ResponseCode.ERROR, false, e.getMessage());");
        updateIdMethod.addBodyLine("}");
    }

    /**
     * select by id
     *
     * @param shortName
     * @param shortModelParam
     * @param modelClazzDTOType
     * @param exampleClass
     * @param exampleShort
     * @param dtoParameter
     * @param daoFieldName
     * @param selectIdMethod
     */
    private void generateSelectByIdCode(String shortName, String shortModelParam, FullyQualifiedJavaType modelClazzDTOType, String exampleClass, String exampleShort, String dtoParameter, String daoFieldName, Method selectIdMethod) {
        selectIdMethod.addBodyLine(String.format("Result<%s> result = new Result<%s>();", modelClazzDTOType.getShortName(), modelClazzDTOType.getShortName()));
        selectIdMethod.addBodyLine("if (id == null) {");
        selectIdMethod.addBodyLine("result.setResult(ResponseCode.PARAMETER_ERROR, null, \"参数不可为空\");");
        selectIdMethod.addBodyLine("}");
        selectIdMethod.addBodyLine(String.format("%s example = new %s();", exampleShort, exampleShort));
        selectIdMethod.addBodyLine("example.createCriteria().andIsDelEqualTo(0).andIdEqualTo(id);");
        selectIdMethod.addBodyLine(String.format("List<%s> resultLists = %s.selectByExample(example);", shortName, daoFieldName));
        selectIdMethod.addBodyLine("if (resultLists.size() > 0) {");
        selectIdMethod.addBodyLine(String.format("%s %s = resultLists.get(0);", shortName, shortModelParam));
        selectIdMethod.addBodyLine(String.format("%s %s= NewBstBeanUtils.po2dto(%s, %s.class);", modelClazzDTOType.getShortName(), dtoParameter, shortModelParam, modelClazzDTOType.getShortName()));
        selectIdMethod.addBodyLine(String.format("return result.setResult(%s, \"ok\");", dtoParameter));
        selectIdMethod.addBodyLine("} else {");
        selectIdMethod.addBodyLine("return result.setResult(ResponseCode.NULL_RESULT, null, \"无结果\");");
        selectIdMethod.addBodyLine("}");
    }

    /**
     * delete by id logic
     *
     * @param shortName
     * @param shortModelParam
     * @param exampleShort
     * @param daoFieldName
     * @param delMethod
     */
    private void generateDeleteIdLogicCode(String shortName, String shortModelParam, String exampleShort, String daoFieldName, Method delMethod) {
        delMethod.addBodyLine("Result<Boolean> result = new Result<Boolean>();");
        delMethod.addBodyLine("if (id == null) {");
        delMethod.addBodyLine("return result.setResult(ResponseCode.PARAMETER_ERROR, false, \"参数不可为空\");");
        delMethod.addBodyLine("}\n\t\t//where");
        delMethod.addBodyLine(String.format("%s example = new %s();", exampleShort, exampleShort));
        delMethod.addBodyLine("example.createCriteria().andIdEqualTo(id).andIsDelEqualTo(0);\n\t\t//update");
        delMethod.addBodyLine(String.format("%s %s = new %s();", shortName, shortModelParam, shortName));
        delMethod.addBodyLine(String.format("%s.setIsDel(1);", shortModelParam));
        delMethod.addBodyLine(String.format("%s.setGmtModify(new Date());", shortModelParam));
        delMethod.addBodyLine(String.format("%s.setModifierId(userId);", shortModelParam));
        delMethod.addBodyLine("try {");
        delMethod.addBodyLine(String.format("%s.updateByExampleSelective(%s, example);", daoFieldName, shortModelParam));
        delMethod.addBodyLine("return result.setResult(true, \"ok\");");
        delMethod.addBodyLine("} catch (Exception e) {");
        delMethod.addBodyLine("e.printStackTrace();");
        delMethod.addBodyLine("return result.setResult(ResponseCode.ERROR, false, e.getMessage());");
        delMethod.addBodyLine("}");
    }

    /**
     * add
     *
     * @param shortName
     * @param dtoParameter
     * @param daoFieldName
     * @param addMethodBody
     */
    private void generateServiceAddCodes(String shortName, String dtoParameter, String daoFieldName, List<String> addMethodBody) {
        addMethodBody.add("Result<Integer> result = new Result<Integer>();");
        addMethodBody.add("if (" + dtoParameter + " == null) {");
        addMethodBody.add("return result.setResult(ResponseCode.PARAMETER_ERROR, null, \"参数不能为空\");");
        addMethodBody.add("}");
        addMethodBody.add("try {");
        addMethodBody.add(String.format("%s %s = NewBstBeanUtils.dto2po(%s, %s.class);", shortName, firstCharToLowCase(shortName), dtoParameter, shortName));
        addMethodBody.add("//判断对象是否为空");
        addMethodBody.add(String.format("if (JSON.parseObject(JSON.toJSONString(%s)).size() == 0) {", firstCharToLowCase(shortName)));
        addMethodBody.add("return result.setResult(ResponseCode.PARAMETER_ERROR, null, \"空对象\");");
        addMethodBody.add("}");
        addMethodBody.add(String.format("%s.insertSelective(%s);", daoFieldName, firstCharToLowCase(shortName)));
        addMethodBody.add(String.format("return result.setResult(%s.getId(), \"ok\");", firstCharToLowCase(shortName)));
        addMethodBody.add("} catch (Exception e) {");
        addMethodBody.add("e.printStackTrace();");
        addMethodBody.add("return result.setResult(ResponseCode.ERROR, null, e.getMessage());");
        addMethodBody.add("}");
    }


}